﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Funkcje;

namespace AlgorytmyGenetyczne.Historia
{
    public class Historia
    {
        public List<PopulacjaHistoria> ListaPopulacji { get; private set; }
        public List<double> ListaNajlepszychOcen { get; private set; }
        public List<double> ListaNajgorszychOcen { get; private set; }
        public List<double> ListaSrednichOcen { get; private set; }
        public List<double> ListaNajlepszychRozwiazan { get; private set; }
        public List<double> ListaNajgorszychRozwiazan { get; private set; }
        public List<double> ListaSrednichRozwiazan { get; private set; }
        private PopulacjaHistoria BiezacaPopulacja { get; set; }
        /// <summary>
        /// Co ile krokow ewolucji zachowywac informacje o calej populacji
        /// </summary>
        public int InterwalPopulacje { get; set; }
        /// <summary>
        /// Co ile krokow ewolucji zbierac informacje statystyczne (najlepszy, najgorszy osobnik i srednia rozwiazan)
        /// </summary>
        public int InterwalStatystyki { get; set; }
        public int LicznikKrokow { get; private set; }

        public Historia()
        {
            ListaPopulacji = new List<PopulacjaHistoria>();
            ListaNajlepszychOcen = new List<double>();
            ListaNajgorszychOcen = new List<double>();
            ListaSrednichOcen = new List<double>();
            BiezacaPopulacja = new PopulacjaHistoria();
            ListaNajgorszychRozwiazan = new List<double>();
            ListaNajlepszychRozwiazan = new List<double>();
            ListaSrednichRozwiazan = new List<double>();
        }

        public Historia(int interwalStatystyki, int interwalPopulacje)
            : this()
        {
            InterwalPopulacje = interwalPopulacje;
            InterwalStatystyki = interwalStatystyki;
        }

        private bool sprawdzCzyZapisacPopulacje()
        {
            if (InterwalPopulacje != 0 && LicznikKrokow % InterwalPopulacje == 0)
            {
                return true;
            }
            return false;
        }

        public void dodajOsobnikaDoHistoriiPopulacji(double[] argumenty, double wartoscFunkcji)
        {
            double x = argumenty[0];
            double y;
            if (argumenty.Length < 2)
            {
                y = 0.0;
            }
            else { y = argumenty[1]; }


            BiezacaPopulacja.Osobnicy.Add(new OsobnikHistoria(new Point3D(x, y, wartoscFunkcji)));
        }

        public void zbierajStatystyki(Populacja populacja)
        {
            LicznikKrokow++;
            if (InterwalStatystyki != 0)
            {
                if (LicznikKrokow == 0 || LicznikKrokow % InterwalStatystyki == 0)
                {
                    double najgorszaOcena = double.PositiveInfinity;
                    double najlepszaOcena = double.NegativeInfinity;
                    double sumaOcen = 0;

                    foreach (Osobnik osobnik in populacja.Osobnicy)
                    {
                        if (osobnik.Ocena > najlepszaOcena)
                        {
                            najlepszaOcena = osobnik.Ocena;
                        }
                        if (osobnik.Ocena < najgorszaOcena)
                        {
                            najgorszaOcena = osobnik.Ocena;
                        }
                        sumaOcen += osobnik.Ocena;
                    }

                    ListaNajlepszychOcen.Add(najlepszaOcena);
                    ListaNajgorszychOcen.Add(najgorszaOcena);
                    ListaSrednichOcen.Add(sumaOcen / populacja.Osobnicy.Count);

                    double najgorszeRozwiazanie = double.PositiveInfinity;
                    double najlepszeRozwiazanie = double.NegativeInfinity;
                    double sumaRozwiazan = 0;

                    foreach (OsobnikHistoria osobnikHistoria in BiezacaPopulacja.Osobnicy)
                    {
                        if (osobnikHistoria.Punkt.z > najgorszeRozwiazanie)
                        {
                            najlepszeRozwiazanie = osobnikHistoria.Punkt.z;
                        }
                        if (osobnikHistoria.Punkt.z < najgorszeRozwiazanie)
                        {
                            najgorszeRozwiazanie = osobnikHistoria.Punkt.z;
                        }
                        sumaRozwiazan += osobnikHistoria.Punkt.z;
                    }

                    ListaNajlepszychRozwiazan.Add(najlepszeRozwiazanie);
                    ListaNajgorszychRozwiazan.Add(najgorszeRozwiazanie);
                    ListaSrednichRozwiazan.Add(sumaRozwiazan / BiezacaPopulacja.Osobnicy.Count);
                }
            }

            if (sprawdzCzyZapisacPopulacje())
            {
                ListaPopulacji.Add(new PopulacjaHistoria(BiezacaPopulacja));
            }
            BiezacaPopulacja.Osobnicy.Clear();

        }

        public override string ToString()
        {
            StringBuilder str = new StringBuilder();
            for (int i = 0; i < LicznikKrokow; i++)
            {
                str.Append(ListaNajlepszychRozwiazan[i]);
                str.Append("\t");
                str.Append(ListaNajgorszychRozwiazan[i]);
                str.Append("\t");
                str.Append(ListaSrednichRozwiazan[i]);
                str.Append("\t");
                str.Append(ListaSrednichOcen[i]);
                str.AppendLine();
            }
            return str.ToString();
        }

        public void zapiszDoPliku(string sciezka, string znacznik, string numerBadania)
        {
            FileInfo fileInfo = new FileInfo(sciezka);
            DirectoryInfo directoryInfo = fileInfo.Directory;

            FileStream fileStream = new FileStream(directoryInfo.FullName + "\\" + znacznik + "stats_" + numerBadania + ".txt", FileMode.CreateNew, FileAccess.Write);
            StreamWriter streamWriter = new StreamWriter(fileStream);
            streamWriter.Write(ToString());
            streamWriter.Close();
        }

        public void zapiszPopulacjeDoPliku(string sciezka, string znacznik, string numerBadania)
        {
            FileInfo fileInfo = new FileInfo(sciezka);
            DirectoryInfo directoryInfo = fileInfo.Directory;

            FileStream fileStream = new FileStream(directoryInfo.FullName + "\\" + znacznik + "populacje_" + numerBadania + ".txt", FileMode.CreateNew, FileAccess.Write);
            StreamWriter streamWriter = new StreamWriter(fileStream);
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < ListaPopulacji.Count; i++)
            {
                stringBuilder.AppendLine().Append("========  ").Append(i + 1).Append("  ========").AppendLine();
                stringBuilder.Append(ListaPopulacji[i]);
            }
            streamWriter.Write(stringBuilder.ToString());
            streamWriter.Close();
        }


    }
}
